package server

import (
	"log"
	"net/http"
	"sync"
	"wxp2p/common"

	"github.com/gorilla/websocket"
)

var upgrader = websocket.Upgrader{} // use default options

var client_conn_map = make(map[string]*websocket.Conn, 0)
var server_conn_map = make(map[string]*websocket.Conn, 0)

var conn_client_map = make(map[*websocket.Conn]string, 0)
var conn_server_map = make(map[*websocket.Conn]string, 0)

var client_conn_map_mutx sync.RWMutex
var server_conn_map_mutx sync.RWMutex
var conn_client_map_mutx sync.RWMutex
var conn_server_map_mutx sync.RWMutex

func deleteClientConnByConn(conn *websocket.Conn) (string, bool) {
	conn_client_map_mutx.RLock()
	clientId, ok := conn_client_map[conn]
	conn_client_map_mutx.RUnlock()
	if ok {
		conn.Close()
		conn_client_map_mutx.Lock()
		delete(conn_client_map, conn)
		conn_client_map_mutx.Unlock()
		client_conn_map_mutx.Lock()
		delete(client_conn_map, clientId)
		client_conn_map_mutx.Unlock()
		log.Println("delete client client", clientId)
		return clientId, true
	} else {
		return "", false
	}
}

func deleteServerConnByConn(conn *websocket.Conn) (string, bool) {
	conn_server_map_mutx.RLock()
	clientId, ok := conn_server_map[conn]
	conn_server_map_mutx.RUnlock()
	if ok {
		conn.Close()
		conn_server_map_mutx.Lock()
		delete(conn_server_map, conn)
		conn_server_map_mutx.Unlock()
		server_conn_map_mutx.Lock()
		delete(server_conn_map, clientId)
		server_conn_map_mutx.Unlock()
		log.Println("delete server client", clientId)
		return clientId, true
	} else {
		return "", false
	}
}

func deleteClientConnByClientId(clientId string) {
	client_conn_map_mutx.RLock()
	conn, ok := client_conn_map[clientId]
	client_conn_map_mutx.RUnlock()
	if ok {
		conn.Close()
		conn_client_map_mutx.Lock()
		delete(conn_client_map, conn)
		conn_client_map_mutx.Unlock()
		client_conn_map_mutx.Lock()
		delete(client_conn_map, clientId)
		client_conn_map_mutx.Unlock()
		log.Println("delete client client", clientId)
	}
}

func deleteServerConnByClientId(clientId string) {
	server_conn_map_mutx.RLock()
	conn, ok := server_conn_map[clientId]
	server_conn_map_mutx.RUnlock()
	if ok {
		conn.Close()
		conn_server_map_mutx.Lock()
		delete(conn_server_map, conn)
		conn_server_map_mutx.Unlock()
		server_conn_map_mutx.Lock()
		delete(server_conn_map, clientId)
		server_conn_map_mutx.Unlock()
		log.Println("delete server client", clientId)
	}
}
func addServerConn(clientId string, conn *websocket.Conn) {
	server_conn_map_mutx.Lock()
	server_conn_map[clientId] = conn
	server_conn_map_mutx.Unlock()
	conn_server_map_mutx.Lock()
	conn_server_map[conn] = clientId
	conn_server_map_mutx.Unlock()
	log.Println("new server client:", clientId)
}
func addClientConn(clientId string, conn *websocket.Conn) {
	client_conn_map_mutx.Lock()
	client_conn_map[clientId] = conn
	client_conn_map_mutx.Unlock()
	conn_client_map_mutx.Lock()
	conn_client_map[conn] = clientId
	conn_client_map_mutx.Unlock()
	log.Println("new client client:", clientId)
}

func SignalHandler(w http.ResponseWriter, r *http.Request) {
	c, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Print("upgrade error:", err)
		return
	}
	// c.SetCloseHandler(func(code int, text string) error {
	// 	deleteClientConnByConn(c)
	// 	deleteServerConnByConn(c)
	// 	return nil
	// })
	// 客户端断开，服务端保留，服务端断开，客户端断开：保证服务端重登录后，客户端可以连接
	defer func() {
		clientId, ok := deleteServerConnByConn(c)
		if ok {
			deleteClientConnByClientId(clientId)
		}
		deleteClientConnByConn(c)
		c.Close()
	}()
	for {
		sig := common.P2PSignal{}
		err := c.ReadJSON(&sig)
		if err != nil {
			break
		}
		// 注册server-client
		if sig.SigType == common.ERegClient {
			// 判断clientId是否被注册了，如果注册了，断开连接，通知客户端修改clientId
			server_conn_map_mutx.RLock()
			_, ok := server_conn_map[sig.ClientId]
			server_conn_map_mutx.RUnlock()
			if ok { //clientId重复了，通知连接的serverclient重新定义id
				res := common.P2PSignal{ClientType: common.EServer, SigType: common.EClientIdDublite, Content: "ID重复,请重新定义"}
				c.WriteJSON(res)
				break
			} else {
				addServerConn(sig.ClientId, c)
				continue
			}
		}
		// clientclient发起连接请求
		if sig.SigType == common.ELinkClient {
			// 判断是否已经有客户端连接主机，有的话给出提示
			client_conn_map_mutx.RLock()
			_, ok := client_conn_map[sig.ClientId]
			client_conn_map_mutx.RUnlock()
			server_conn_map_mutx.RLock()
			_, serverok := server_conn_map[sig.ClientId]
			server_conn_map_mutx.RUnlock()
			if !serverok {
				res := common.P2PSignal{ClientType: common.EServer, SigType: common.ENoServerClient, Content: "没有注册的ID"}
				c.WriteJSON(res)
				break
			}
			if ok {
				res := common.P2PSignal{ClientType: common.EServer, SigType: common.EClientIdDublite, Content: "已经有一个客户端连接到此ID"}
				c.WriteJSON(res)
				break
			}
			addClientConn(sig.ClientId, c)
			// 准备就绪，通知serverclient开始打洞
			c.WriteJSON(common.P2PSignal{ClientId: sig.ClientId, ClientType: common.EServer, SigType: common.EBeginHole})
			continue
		}
		// 链接信息和打洞信息直接转发，没有找到则通知掉线
		if sig.SigType == common.ECandidate || sig.SigType == common.ESdp {
			if sig.ClientType == common.EClientClient {
				server_conn_map_mutx.RLock()
				recConn, ok := server_conn_map[sig.ClientId]
				server_conn_map_mutx.RUnlock()
				if ok {
					err := recConn.WriteJSON(sig)
					if err != nil { //如果是掉线，应该保证连接从mao中删除了
						deleteServerConnByClientId(sig.ClientId)
					}
				}
			} else {
				client_conn_map_mutx.RLock()
				recConn, ok := client_conn_map[sig.ClientId]
				client_conn_map_mutx.RUnlock()
				if ok {
					err := recConn.WriteJSON(sig)
					if err != nil { //如果是掉线，应该保证连接从map中删除了
						deleteClientConnByClientId(sig.ClientId)
					}
				}
			}
		}
	}
}

func SignalHandlerN(w http.ResponseWriter, r *http.Request) {
	c, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Print("upgrade error:", err)
		return
	}

	// 客户端断开，服务端保留，服务端断开，客户端断开：保证服务端重登录后，客户端可以连接
	defer func() {
		clientId, ok := deleteServerConnByConn(c)
		if ok {
			deleteClientConnByClientId(clientId)
		}
		deleteClientConnByConn(c)
		c.Close()
	}()
	for {
		sig := common.P2PSignal{}
		err := c.ReadJSON(&sig)
		if err != nil {
			break
		}
		// 注册server-client
		if sig.SigType == common.ERegClient {
			// 判断clientId是否被注册了，如果注册了，断开连接，通知客户端修改clientId
			server_conn_map_mutx.RLock()
			_, ok := server_conn_map[sig.ClientId]
			server_conn_map_mutx.RUnlock()
			if ok { //clientId重复了，通知连接的serverclient重新定义id
				res := common.P2PSignal{ClientType: common.EServer, SigType: common.EClientIdDublite, Content: "ID重复,请重新定义"}
				c.WriteJSON(res)
				break
			} else {
				addServerConn(sig.ClientId, c)
				c.WriteJSON(common.P2PSignal{ClientId: sig.ClientId, ClientType: common.EServer, SigType: common.ERegOK})
				continue
			}
		}
		// clientclient发起连接请求
		if sig.SigType == common.ELinkClient {
			// 判断是否已经有客户端连接主机，有的话给出提示
			client_conn_map_mutx.RLock()
			_, ok := client_conn_map[sig.ClientId]
			client_conn_map_mutx.RUnlock()
			server_conn_map_mutx.RLock()
			_, serverok := server_conn_map[sig.ClientId]
			server_conn_map_mutx.RUnlock()
			if !serverok {
				res := common.P2PSignal{ClientType: common.EServer, SigType: common.ENoServerClient, Content: "没有注册的ID"}
				c.WriteJSON(res)
				break
			}
			if ok {
				res := common.P2PSignal{ClientType: common.EServer, SigType: common.EClientIdDublite, Content: "已经有一个客户端连接到此ID"}
				c.WriteJSON(res)
				break
			}
			addClientConn(sig.ClientId, c)
			// 准备就绪，通知serverclient开始打洞
			c.WriteJSON(common.P2PSignal{ClientId: sig.ClientId, ClientType: common.EServer, SigType: common.ELinkOK})
			continue
		}
		// 链接信息和打洞信息直接转发，没有找到则通知掉线
		// if sig.SigType == common.ECandidate || sig.SigType == common.ESdp ||sig.SigType==common.ECreateAnswer{
		if true {
			if sig.ClientType == common.EClientClient {
				server_conn_map_mutx.RLock()
				recConn, ok := server_conn_map[sig.ClientId]
				server_conn_map_mutx.RUnlock()
				if ok {
					err := recConn.WriteJSON(sig)
					if err != nil { //如果是掉线，应该保证连接从mao中删除了
						deleteServerConnByClientId(sig.ClientId)
					}
				}
			} else {
				client_conn_map_mutx.RLock()
				recConn, ok := client_conn_map[sig.ClientId]
				client_conn_map_mutx.RUnlock()
				if ok {
					err := recConn.WriteJSON(sig)
					if err != nil { //如果是掉线，应该保证连接从map中删除了
						deleteClientConnByClientId(sig.ClientId)
					}
				}
			}
		}
	}
}
